package com.kitty.game.scene.aoi;

import com.kitty.common.utils.SpringUtils;
import com.kitty.game.fight.service.BroadcastService;
import com.kitty.game.role.model.Role;
import com.kitty.game.role.service.RoleService;
import com.kitty.game.team.message.RespTeamMove;
import com.kitty.game.team.service.TeamService;
import com.kitty.game.utils.Const;
import com.kitty.mina.message.Message;
import com.kitty.mina.message.MessagePusher;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

public class Scene extends AOI {


    private BroadcastService service = SpringUtils.getBroadcastService();
    private RoleService roleService = SpringUtils.getRoleService();
    private TeamService teamService = SpringUtils.getTeamService();
    /**
     * 可视距离
     */
    private final static int DISTANCE = 20;

    private Node _head;

    private Node _tail;

    private Map<Long, Node> allNodes = new HashMap<>();

    public Scene() {
        _head = new Node(Long.MIN_VALUE, 0, 0);
        _tail = new Node(Long.MAX_VALUE, 0, 0);

        _head.xNext = _tail;
        _head.yNext = _tail;

        _tail.xPrev = _head;
        _tail.yPrev = _head;
    }

    private void addActor(Node node) {
        allNodes.put(node.id, node);
        /**X轴处理*/
        Node cur = _head.xNext;
        while (cur != null) {
            if (cur.x > node.x || cur == _tail) {
                node.xNext = cur;
                node.xPrev = cur.xPrev;
                cur.xPrev.xNext = node;
                cur.xPrev = node;
                break;
            }
            cur = cur.xNext;
        }

        /**Y轴处理*/
        cur = _head.yNext;
        while (cur != null) {
            if (cur.y > node.y || cur == _tail) {
                node.yNext = cur;
                node.yPrev = cur.yPrev;
                cur.yPrev.yNext = node;
                cur.yPrev = node;
                break;
            }
            cur = cur.yNext;
        }
    }


    private Node getNodeByRole(Role role) {
        Node node = allNodes.get(role.getUid());
        if (node == null) {
            node = new Node(role.getUid(), role.getPos().getX(), role.getPos().getY());
            addActor(node);
        }
        return node;
    }

    private void leave(Node node) {
        if (node.xPrev != null) {
            node.xPrev.xNext = node.xNext;
        }
        if (node.xNext != null) {
            node.xNext.xPrev = node.xPrev;
        }
        if (node.yPrev != null) {
            node.yPrev.yNext = node.yNext;
        }
        if (node.yNext != null) {
            node.yNext.yPrev = node.yPrev;
        }
        node.xPrev = null;
        node.xNext = null;
        node.yPrev = null;
        node.yNext = null;
    }

    /**
     * 返回可视单位
     */
    private Set<Long> getVisualObjects(Node node) {
        /**可视列表*/
        Set<Long> visuals = new HashSet<>();
        if (node == null) {

            return visuals;
        }
        /**往后找*/
        Node cur = node.xNext;
        while (cur != _tail) {
            if (cur.x - node.x > DISTANCE) {
                break;
            } else {
                int inteval = node.y - cur.y;
                if (inteval >= -DISTANCE && inteval <= DISTANCE) {
                    visuals.add(cur.id);
                }
            }
            cur = cur.xNext;
        }
        /**往前找*/
        cur = node.xPrev;
        while (cur != _head) {
            if ((node.x - cur.x) > DISTANCE) {
                break;
            } else {
                int inteval = node.y - cur.y;
                if (inteval >= -DISTANCE && inteval <= DISTANCE) {
                    visuals.add(cur.id);
                }
            }
            cur = cur.xPrev;
        }
        return visuals;
    }

    /**
     * 进入场景
     */
    @Override
    public void enter(Role role) {
        Node node = allNodes.get(role.getUid());
        if (node != null) {
        } else {
            node = getNodeByRole(role);
        }
        Set<Long> enters = getVisualObjects(node);
        sendAppear(role, enters);
    }

    /**
     * 离开场景
     */
    @Override
    public void leave(long id) {
        /**因为下线所以找不到在线角色 这里使用这个方法来取Role*/
        Role role = SpringUtils.getPlayerService().getPlayerBy(id);
        Node node = getNodeByRole(role);
        Set<Long> leaves = getVisualObjects(node);
        sendDisappear(role, leaves);
        leave(node);
        allNodes.remove(id);
    }

    /**
     * 移动坐标
     */
    @Override
    public void move(Role role) {
//        logger.error("移动广播=={}=={}", role.getUid());
        /**旧的可视集合*/
        Node node = getNodeByRole(role);
        Set<Long> oldSet = getVisualObjects(node);
        leave(node);
        node.x = role.getPos().getX();
        node.y = role.getPos().getY();
        addActor(node);
        /**新的可视集合*/
        Set<Long> newSet = getVisualObjects(node);
        /**oldSet与newSet的交集是moves*/
        Set<Long> moves = oldSet.stream().filter(newSet::contains).collect(Collectors.toSet());
        /**newSet与moves的差集是entes*/
        Set<Long> enters = newSet.stream().filter(id -> !moves.contains(id)).collect(Collectors.toSet());
        /**oldSet与moves的差集是leaves*/
        Set<Long> leaves = oldSet.stream().filter(id -> !moves.contains(id)).collect(Collectors.toSet());
        sendAppear(role, enters);
        sendMove(role, moves);
        sendDisappear(role, leaves);
//        logger.error("移动广播=={}=={}", Json.toJson(moves),Json.toJson(enters));
    }

    /**
     * 发送其他包用这个
     */
    @Override
    public void sendMessages(Role role, Message... messages) {
        Node node = getNodeByRole(role);
        Set<Long> ids = getVisualObjects(node);
        sendMessages(role, ids, messages);
    }

    private void sendMessages(Role role, Set<Long> ids, Message... messages) {
        MessagePusher.pushMessages(role, messages);
        if (ids.size() <= 0) {
            return;
        }
        for (long targetId : ids) {
            Role target = roleService.getOnlinePlayer(targetId);
            if (target != null && service.inSameScene(role, target)) {
                MessagePusher.pushMessages(target, messages);
            }
        }
    }


    /**
     * 发送移动
     */
    private void sendMove(Role selfRole, Set<Long> moves) {
        Message movePacket = service.getMovePacket(selfRole);
        MessagePusher.pushMessage(selfRole, movePacket);
        if (moves.size() <= 0) {
            return;
        }
        RespTeamMove respTeamMove = null;
        /**队伍不为空 并且没暂离*/
        if (teamService.isInTeam(selfRole)) {
            respTeamMove = new RespTeamMove(selfRole.getRoleId(), selfRole.getPos().getX(),
                    selfRole.getPos().getY(), selfRole.getPos().getMapId());
        }
        /**发移动包*/
        for (long targetId : moves) {
            Role target = roleService.getOnlinePlayer(targetId);
            if (target != null && service.inSameScene(selfRole, target)) {
                MessagePusher.pushMessage(target, movePacket);
                MessagePusher.pushMessage(target, respTeamMove);
            }
        }
    }

    /**
     * 发送外观
     */
    private void sendAppear(Role selfRole, Set<Long> enters) {
        Message appear = service.getAppear(selfRole);
        Message petAppear = service.getPetAppear(selfRole);
        Message titleInfo = service.getTitleInfo(selfRole);

        MessagePusher.pushMessage(selfRole, titleInfo);
        if (enters.size() <= 0) {
            return;
        }
        for (long targetId : enters) {
            Role target = roleService.getOnlinePlayer(targetId);
            if (target != null && service.inSameScene(selfRole, target)) {
                Message oAppear = service.getAppear(target);
                Message oTitleInfo = service.getTitleInfo(target);
                Message oPetAppear = service.getPetAppear(target);

                MessagePusher.pushMessage(selfRole, oAppear);
                MessagePusher.pushMessage(selfRole, oPetAppear);
                MessagePusher.pushMessage(selfRole, oTitleInfo);

                /**进入视野是相互的，所以需要发送2条通知*/
                MessagePusher.pushMessage(target, appear);
                MessagePusher.pushMessage(target, petAppear);
                MessagePusher.pushMessage(target, titleInfo);
            }
        }
    }

    /**
     * 消失外观
     */
    private void sendDisappear(Role selfRole, Set<Long> leaves) {
        if (leaves.size() <= 0) {
            return;
        }
        Message petDisAppear = service.getDisAppear(selfRole.getFollowPetId(), Const.PET);
        Message disAppear = service.getDisAppear(selfRole);
        /**离开场景后应该清空对象的AOI对象列表，所以只需通知仍在场景中的对象*/
        for (long targetId : leaves) {
            Role target = roleService.getOnlinePlayer(targetId);
            if (target != null) {
                MessagePusher.pushMessage(target, disAppear);
                MessagePusher.pushMessage(target, petDisAppear);

                MessagePusher.pushMessage(selfRole, service.getDisAppear(target));
                MessagePusher.pushMessage(selfRole, service.getDisAppear(target.getFollowPetId(), Const.PET));
            }
        }
    }
}

